import typing
from datetime import datetime
from threading import RLock
from typing import IO
from typing import Any
from typing import AnyStr
from typing import BinaryIO
from typing import Callable
from typing import Collection
from typing import Iterable
from typing import Iterator
from typing import List
from typing import Mapping
from typing import Optional
from typing import Text
from typing import Tuple

from .base import FS
from .enums import ResourceType
from .info import Info
from .info import RawInfo
from .permissions import Permissions
from .subfs import SubFS
from .walk import BoundWalker

_T = typing.TypeVar("_T", bound="FS")
_OpendirFactory = Callable[[_T, Text], SubFS[_T]]
_F = typing.TypeVar("_F", bound="FS", covariant=True)
_W = typing.TypeVar("_W", bound="WrapFS[FS]")

class WrapFS(FS, typing.Generic[_F]):
    wrap_name: Optional[Text] = ...

    def __init__(self, wrap_fs: _F) -> None: ...
    def __repr__(self) -> Text: ...
    def __str__(self) -> Text: ...
    def delegate_path(self, path: Text) -> Tuple[_F, Text]: ...
    def delegate_fs(self) -> _F: ...
    def appendbytes(self, path: Text, data: bytes) -> None: ...
    def appendtext(
        self,
        path: Text,
        text: Text,
        encoding: Text = ...,
        errors: Optional[Text] = ...,
        newline: Text = ...,
    ) -> None: ...
    def getinfo(
        self, path: Text, namespaces: Optional[Collection[Text]] = ...
    ) -> Info: ...
    def listdir(self, path: Text) -> List[Text]: ...
    def lock(self) -> RLock: ...
    def makedir(
        self, path: Text, permissions: Optional[Permissions] = ..., recreate: bool = ...
    ) -> SubFS[FS]: ...
    def move(self, src_path: Text, dst_path: Text, overwrite: bool = ...) -> None: ...
    def movedir(self, src_path: Text, dst_path: Text, create: bool = ...) -> None: ...
    def openbin(
        self, path: Text, mode: Text = ..., buffering: int = ..., **options: Any
    ) -> BinaryIO: ...
    def remove(self, path: Text) -> None: ...
    def removedir(self, path: Text) -> None: ...
    def removetree(self, dir_path: Text) -> None: ...
    def scandir(
        self,
        path: Text,
        namespaces: Optional[Collection[Text]] = ...,
        page: Optional[Tuple[int, int]] = ...,
    ) -> Iterator[Info]: ...
    def setinfo(self, path: Text, info: RawInfo) -> None: ...
    def settimes(
        self,
        path: Text,
        accessed: Optional[datetime] = ...,
        modified: Optional[datetime] = ...,
    ) -> None: ...
    def touch(self, path: Text) -> None: ...
    def copy(self, src_path: Text, dst_path: Text, overwrite: bool = ...) -> None: ...
    def copydir(self, src_path: Text, dst_path: Text, create: bool = ...) -> None: ...
    def create(self, path: Text, wipe: bool = ...) -> bool: ...
    def desc(self, path: Text) -> Text: ...
    def download(
        self,
        path: Text,
        file: BinaryIO,
        chunk_size: Optional[int] = ...,
        **options: Any,
    ) -> None: ...
    def exists(self, path: Text) -> bool: ...
    def filterdir(
        self,
        path: Text,
        files: Optional[Iterable[Text]] = ...,
        dirs: Optional[Iterable[Text]] = ...,
        exclude_dirs: Optional[Iterable[Text]] = ...,
        exclude_files: Optional[Iterable[Text]] = ...,
        namespaces: Optional[Collection[Text]] = ...,
        page: Optional[Tuple[int, int]] = ...,
    ) -> Iterator[Info]: ...
    def readbytes(self, path: Text) -> bytes: ...
    def readtext(
        self,
        path: Text,
        encoding: Optional[Text] = ...,
        errors: Optional[Text] = ...,
        newline: Text = ...,
    ) -> Text: ...
    def getmeta(self, namespace: Text = ...) -> Mapping[Text, object]: ...
    def getsize(self, path: Text) -> int: ...
    def getsyspath(self, path: Text) -> Text: ...
    def gettype(self, path: Text) -> ResourceType: ...
    def geturl(self, path: Text, purpose: Text = ...) -> Text: ...
    def hassyspath(self, path: Text) -> bool: ...
    def hasurl(self, path: Text, purpose: Text = ...) -> bool: ...
    def isdir(self, path: Text) -> bool: ...
    def isfile(self, path: Text) -> bool: ...
    def islink(self, path: Text) -> bool: ...
    def makedirs(
        self, path: Text, permissions: Optional[Permissions] = ..., recreate: bool = ...
    ) -> SubFS[FS]: ...
    def open(
        self,
        path: Text,
        mode: Text = ...,
        buffering: int = ...,
        encoding: Optional[Text] = ...,
        errors: Optional[Text] = ...,
        newline: Text = ...,
        line_buffering: bool = ...,
        **options: Any,
    ) -> IO[AnyStr]: ...
    def opendir(
        self: _W, path: Text, factory: Optional[_OpendirFactory[_W]] = ...
    ) -> SubFS[_W]: ...
    def writebytes(self, path: Text, contents: bytes) -> None: ...
    def upload(
        self,
        path: Text,
        file: BinaryIO,
        chunk_size: Optional[int] = ...,
        **options: Any,
    ) -> None: ...
    def writefile(
        self,
        path: Text,
        file: IO[AnyStr],
        encoding: Optional[Text] = ...,
        errors: Optional[Text] = ...,
        newline: Text = ...,
    ) -> None: ...
    def validatepath(self, path: Text) -> Text: ...
    def hash(self, path: Text, name: Text) -> Text: ...
    @property
    def walk(self: _W) -> BoundWalker[_W]: ...
